﻿using System;
using System.Collections.Generic;
using System.Xml;

namespace NeuralNetwork.Neurons
{
    public class Neuron
    {
        private string id;

        public Network network = null;
        public List<Axon> axons = new List<Axon>();
        public List<Axon> dendrites = new List<Axon>();        

        protected double error = 0;
        protected double potential = 0;
        protected double value = 0;
        
        public Neuron(Network network)
        {
            this.network = network;            
            id = network.GetUniqueID();            
        }
        
        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        public override string ToString()
        {
            return id.ToString();
        }

        public double Value
        {
            get { return value; }
        }

        public double Error
        {
            get { return error; }
            set { error = value; }
        }

        public double Potential
        {
            get { return potential; }
            set { potential = value; }
        }
       
        virtual public void Absorb(double charge)
        {
            potential += charge;
        }

        virtual public void Reset()
        {
            Potential = 0;
            error = 0;
            value = 0;
        }

        virtual public bool Update()
        {
            // Send output value and feed it to connected neurons
            value = network.activation.Call(potential) - network.ActivationThreshold;
            if (value > 0)
                foreach (Axon axon in axons) axon.Absorb(value);
            
            return (value > 0);
        }

        virtual public void Revert()
        {
            foreach (Axon a in axons) a.Revert();
        }

        virtual public void Prune()
        {
            Axon a;
            for(int i = axons.Count - 1; i >= 0; i--) 
            {
                a = (Axon)axons[i];
                if (a.Prune(network.PrunningLevel))
                    axons.RemoveAt(i);
            }
        }

        virtual public XmlNode Save(XmlDocument doc, XmlNode parent)
        {
            XmlNode node = network.AddChildToNode(doc, parent, this.GetType().Name, null);
            network.AddIDToNode(doc, node, id);

            return node;
        }

        virtual public void Load(XmlNode neuronNode)
        {
        }
    }
}
